﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Effects;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Veralkohol.Converters;

namespace Veralkohol
{
    /// <summary>
    /// Follow steps 1a or 1b and then 2 to use this custom control in a XAML file.
    ///
    /// Step 1a) Using this custom control in a XAML file that exists in the current project.
    /// Add this XmlNamespace attribute to the root element of the markup file where it is 
    /// to be used:
    ///
    ///     xmlns:MyNamespace="clr-namespace:Veralkohol.MyControls"
    ///
    ///
    /// Step 1b) Using this custom control in a XAML file that exists in a different project.
    /// Add this XmlNamespace attribute to the root element of the markup file where it is 
    /// to be used:
    ///
    ///     xmlns:MyNamespace="clr-namespace:Veralkohol.MyControls;assembly=Veralkohol.MyControls"
    ///
    /// You will also need to add a project reference from the project where the XAML file lives
    /// to this project and Rebuild to avoid compilation errors:
    ///
    ///     Right click on the target project in the Solution Explorer and
    ///     "Add Reference"->"Projects"->[Browse to and select this project]
    ///
    ///
    /// Step 2)
    /// Go ahead and use your control in the XAML file.
    ///
    ///     <MyNamespace:AlcoholDiagramPoint/>
    ///
    /// </summary>
    public class AlcoholDiagramPoint : Control, INotifyPropertyChanged
    {
        public event EventHandler<AlcoholicPointSelectedEventArgs> PointSelected;

        #region LastReferencePoint - DRpop

        public AlcoholDiagramPoint LastReferencePoint
        {
            get { return (AlcoholDiagramPoint)GetValue(LastReferencePointProperty); }
            set { SetValue(LastReferencePointProperty, value); }
        }

        // Using a DependencyProperty as the backing store for LastReference.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty LastReferencePointProperty =
            DependencyProperty.Register("LastReferencePoint", typeof(AlcoholDiagramPoint), typeof(AlcoholDiagramPoint), 
            new PropertyMetadata(null,new PropertyChangedCallback(LastReferencePointChangedCallback)));

        private static void LastReferencePointChangedCallback(DependencyObject sender, DependencyPropertyChangedEventArgs args)
        {
           AlcoholDiagramPoint control = sender as AlcoholDiagramPoint;
            //Next line only add REMAINING thousandths
           control.Thousandths = AlcoholDiagramPoint.GetRemainingThousandths(control.LastReferencePoint.DrinkTime, control.DrinkTime, control.LastReferencePoint.Thousandths);
        }
        
        #endregion
        
        #region Height - DProp

        public double Height
        {
            get { return (double)GetValue(HeightProperty); }
            set { SetValue(HeightProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Height.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty HeightProperty =
            DependencyProperty.Register("Height", typeof(double), typeof(AlcoholDiagramPoint), new PropertyMetadata(0.0));

        #endregion

        #region Thousands Dprop COMMENTED



        //public double Thousandths
        //{
        //    get
        //    {
        //        double sumpercent = 0;
        //        foreach (var item in Drinks)
        //        {
        //            sumpercent += ((item.Quantity * item.Percentage * 0.8) / Weight);
        //        }

        //        return sumpercent + startthosandths;
        //    }
        //    set { SetValue(ThousandthsProperty, value); }
        //}

        //// Using a DependencyProperty as the backing store for Thousands2.  This enables animation, styling, binding, etc...
        //public static readonly DependencyProperty ThousandthsProperty =
        //    DependencyProperty.Register("Thousandths", typeof(double), typeof(AlcoholDiagramPoint), 
        //    new PropertyMetadata(0.0,ThousChangedCallback));

        //private static void ThousChangedCallback(DependencyObject sender, DependencyPropertyChangedEventArgs args)
        //{
        //    AlcoholDiagramPoint point = sender as AlcoholDiagramPoint;
        //    point.startthosandths = (double)args.NewValue;
        //}
        

        #endregion

        double startthosandths = 0;
        public ObservableCollection<Drink> Drinks { get; set; }
        public double Weight { get; set; }
        public double DrinkTime { get; set; }
        public int ComparableDrinkTime { get; set; }
        

        bool iscp;
        public bool isControlPoint {
            get
            {
                return iscp;
            }
            set
            {
                iscp = value;
                NotifyPropertyChanged("isControlPoint");
            }
        }
        
        public AlcoholDiagramPoint THIS
        {
            get
            {
                return this.MemberwiseClone() as AlcoholDiagramPoint;
            }
        }
        public double Thousandths
        {
            get
            {
                double sumpercent = 0;
                foreach (var item in Drinks)
                {
                    sumpercent += ((item.Quantity * item.Percentage * 0.8) / Weight) ;
                }

                return sumpercent + startthosandths;
            }
            set
            {
                startthosandths = value;
                NotifyPropertyChanged("Thousandths");
                NotifyPropertyChanged("THIS");


                //DropShadowEffect lvlbor = this.GetTemplateChild("littlevertLineb") as DropShadowEffect;
                //if (lvlbor != null)
                //lvlbor.Color = (Color)new Double2ColorConverter().Convert(Thousandths, null, null, null);
            }
        }



        public static double GetRemainingThousandths(double fromTime, double toTime, double thousandths)
        {
            double timedist = toTime - fromTime;
            double newthou = thousandths - timedist * 0.15;

            return newthou <= 0 ? 0 : newthou;
        }

        public double GetZero()
        {
            double time = this.Thousandths / 0.15;
            return this.DrinkTime + time;
        }

        public override string ToString()
        {
            int dd = (int)(DrinkTime / 24);
            int hh = (int)(DrinkTime - dd * 24);
            int mm = (int)Math.Round((DrinkTime - dd * 24 - hh) * 60, 0);
            string drinks = "";
            foreach (var item in Drinks)
            {
                drinks += string.Format("{0} dl | {1} %\n", item.Quantity, item.Percentage);
            }
            if (isControlPoint) return string.Format("{0}.{1}:{2} - {3}‰ -\n{4}", dd, hh, mm, Thousandths, drinks);
            else return string.Format("{0}.{1}:{2} - {3}‰ -", dd, hh, mm, Thousandths);
            //return string.Format("{0} kg | {1}.{2}:{3}\n{4}",Weight, dd, hh, mm,drinks);
        }

        public AlcoholDiagramPoint(double weight, double quantity, double percentage, int day, int hour, int minute, string drn, string imn) : base()
        {
            DrinkTime = day * 24 + hour + (double)minute / 60;
            Drinks = new ObservableCollection<Drink>();
            Drinks.Add(new Drink() { Percentage = percentage, Quantity = quantity, Drinkname = drn, ImageName = imn });
            Weight = weight;
            ComparableDrinkTime = day * 24 * 60 + hour * 60 + minute;
            isControlPoint = true;
        }

        public AlcoholDiagramPoint(double weight, double quantity, double percentage, double drinktime, string drn, string imn) : base()
        {
            int dd = (int)(drinktime / 24);
            int hh = (int)(drinktime - dd * 24);
            int mm = (int)Math.Round((drinktime - dd * 24 - hh) * 60, 0);
            DrinkTime = drinktime;
            Drinks = new ObservableCollection<Drink>();
            Drinks.Add(new Drink() { Percentage = percentage, Quantity = quantity, ImageName = imn, Drinkname=drn });
            Weight = weight;
            ComparableDrinkTime = dd * 24 * 60 + hh * 60 + mm;
            isControlPoint = true;
        }

        public AlcoholDiagramPoint(double weight, int comparableDrinktime)
        {
            DrinkTime = comparableDrinktime/60.0;
            Drinks = new ObservableCollection<Drink>();
            //Drinks.Add(new Drink() { Percentage = 0, Quantity = 0 });
            Weight = weight;
            ComparableDrinkTime = comparableDrinktime;
            isControlPoint = false;
        }

        public AlcoholDiagramPoint()
        {
            
        }
        
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            Drinks.CollectionChanged += (s, e) =>
            {
                NotifyPropertyChanged("Thousandths");
                NotifyPropertyChanged("THIS");
            };

            Line verticalLine = this.GetTemplateChild("vertLine") as Line;
            Border vlbor = this.GetTemplateChild("vertLineb") as Border;
            if (verticalLine != null)
            {
                Binding binding = new Binding("Thousandths");
                binding.Mode = BindingMode.TwoWay;
                binding.RelativeSource = new RelativeSource(RelativeSourceMode.TemplatedParent);
                binding.Converter = new Double2EffectConverter();
                vlbor.SetBinding(Border.EffectProperty, binding);
                

                Binding binding2 = new Binding("isControlPoint");
                binding2.Mode = BindingMode.TwoWay;
                binding2.RelativeSource = new RelativeSource(RelativeSourceMode.TemplatedParent);
                binding2.Converter = new Bool2VisibilityConverter();
                verticalLine.SetBinding(Line.VisibilityProperty, binding2);
            }

            Line littleVertLine = this.GetTemplateChild("littleVertLine") as Line;
            Border lvlbor = this.GetTemplateChild("littleVertLineb") as Border;
            if (littleVertLine != null)
            {
                Binding binding = new Binding("Thousandths");
                binding.Mode = BindingMode.TwoWay;
                binding.RelativeSource = new RelativeSource(RelativeSourceMode.TemplatedParent);
                binding.Converter = new Double2EffectConverter();
                lvlbor.SetBinding(Border.EffectProperty, binding);

                Binding binding2 = new Binding("isControlPoint");
                binding2.Mode = BindingMode.TwoWay;
                binding2.RelativeSource = new RelativeSource(RelativeSourceMode.TemplatedParent);
                binding2.Converter = new NotBool2VisibilityConverter();
                littleVertLine.SetBinding(Line.VisibilityProperty, binding2);
            }

            Line horizontalLine = this.GetTemplateChild("horLine") as Line;
            Border hlineb = this.GetTemplateChild("horLineb") as Border;
            if (horizontalLine != null)
            {
                Binding binding = new Binding("Height");
                binding.Mode = BindingMode.TwoWay;
                binding.RelativeSource = new RelativeSource(RelativeSourceMode.TemplatedParent);
                horizontalLine.SetBinding(Line.Y2Property, binding);

                Binding binding2 = new Binding("Thousandths");
                binding2.Mode = BindingMode.TwoWay;
                binding2.RelativeSource = new RelativeSource(RelativeSourceMode.TemplatedParent);
                binding2.Converter = new Double2EffectConverter();
                hlineb.SetBinding(Border.EffectProperty, binding2);
            }

            Grid containerGrid = this.GetTemplateChild("containerGrid") as Grid;
            if (containerGrid != null)
            {
                containerGrid.MouseEnter += MouseEvent;
                containerGrid.MouseLeave += MouseEvent;
                containerGrid.MouseDown += MouseClick;

                Binding binding3 = new Binding("Height");
                binding3.Mode = BindingMode.TwoWay;
                binding3.RelativeSource = new RelativeSource(RelativeSourceMode.TemplatedParent);
                containerGrid.SetBinding(Grid.HeightProperty, binding3);
            }

        }


        static AlcoholDiagramPoint()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(AlcoholDiagramPoint), new FrameworkPropertyMetadata(typeof(AlcoholDiagramPoint)));
        }

        #region Event handlers

        public event PropertyChangedEventHandler PropertyChanged;
        protected void NotifyPropertyChanged(String propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (null != handler)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        private void MouseEvent(object sender, MouseEventArgs e)
        {
            Grid containerGrid = this.GetTemplateChild("containerGrid") as Grid;
            if (containerGrid != null)
            {
                if (isControlPoint)
                {
                    if (containerGrid.IsMouseOver)
                    {
                        VisualStateManager.GoToElementState(containerGrid, "MouseEnter", true);
                    }
                    else
                    {
                        VisualStateManager.GoToElementState(containerGrid, "MouseLeave", true);
                    }
                }
                else
                {
                    if (containerGrid.IsMouseOver)
                    {
                        VisualStateManager.GoToElementState(containerGrid, "LittleMouseEnter", true);
                    }
                    else
                    {
                        VisualStateManager.GoToElementState(containerGrid, "LittleMouseLeave", true);
                    }
                }
            }
        }

        private void MouseClick(object sender, MouseButtonEventArgs e)
        {
            Grid containerGrid = this.GetTemplateChild("containerGrid") as Grid;
            if (containerGrid != null)
            {
                if (e.ButtonState == MouseButtonState.Pressed)
                {
                    //MessageBox.Show(string.Format("{0} - {1}",
                    //    System.Windows.Forms.Control.MousePosition.X,
                    //    System.Windows.Forms.Control.MousePosition.Y));
                    //if (isControlPoint) VisualStateManager.GoToElementState(containerGrid, "MouseDown", true);
                    //else VisualStateManager.GoToElementState(containerGrid, "LittleMouseDown", true);
                    if (PointSelected != null)
                        PointSelected(this, new AlcoholicPointSelectedEventArgs() { SelectedPoint = this });
                }
            }
        }

        #endregion

    }

    public class AlcoholicPointSelectedEventArgs : EventArgs
    {
        public AlcoholDiagramPoint SelectedPoint { get; set; }
    }

    public class Drink
    {
        public double Quantity { get; set; }
        public double Percentage { get; set; }
        public string Drinkname { get; set; }
        public string ImageName { get; set; }
        public string Bigname {
            get
            {
                return ImageName.Replace("small/", "");
            }
        }

        public static Drink CloneNewInstance(Drink drink)
        {
            return new Drink() { Quantity = drink.Quantity, Percentage = drink.Percentage, Drinkname = drink.Drinkname, ImageName = drink.ImageName };
        }

        public override string ToString()
        {
            return string.Format("{0} dl {1} ({2}%)", Quantity, Drinkname, Percentage);
        }
    }
}
